// 从 合同关联的 业务机会下的 报价,测算,政策中选择 仪器和试剂
// 其中 政策和测算 必须整单选择 
// 报价可以选择单条明细
// 试剂 出现重复: 优先选择测算 其次 报价 
// 选择测算的时候 要判断 测算产品 是否在 已经 选择的产品中 若存在 则不能选择 (可以选择重新做测算或者重新做业务机会或者合同)

// 从血糖仪 申请中 带出血糖仪
public without sharing class ContractProductController {
    
    public String msg {get; private set;}//信息
    public Boolean isErr {get; private set;}//错误
    public Boolean isSuccess {get; private set;}//是否保存成功
    public String backId {get; private set;}
    public String oppId {get; private set;}

    public  Opportunity opp {get;private set;}
    public String searchJson {get;set;}
    public String dataJson {get;private set;}
    public String saveJson {get; set;}
    public String combobx {get;private set;}
    public String companybobx {get;private set;}
    public String accMapJson {get; private set;}
    private Set<Id> oppIdset = new Set<Id>();
    public  Boolean isNew {get;private set;}
    public String appAccId {get; set;}//价格适用客户
    public String appCompany {get; set;}//价格所属公司
    public Boolean isOpp   {get; private set;} 
    private Contract__c con;
    private  Map<String,DataUtil.SObjectBean> stageObjectMap;

    //合作客户 
    private String coCustomer ;

    public Boolean isDealer {get; private set;}
    public ContractProductController() {
         
         backId = System.currentPageReference().getParameters().get('id');
         oppId  = System.currentPageReference().getParameters().get('oppid');

         isOpp = false;
         isNew = true ;
         stageObjectMap = new  Map<String,DataUtil.SObjectBean>();
         opp = new Opportunity();
         con = new Contract__c();


    }

    
    public void setNil(){
        dataJson = '[]';
        searchJson = '{}';
    }
    private void setErr(String message){
        isErr  =true;
        throw new DmlException(message);
    }

    private void getIntentTerinalAccount(Set<Id> oppIds ){
       Map<String,String> accMap = new Map<String,String>();

        for(IntentProduct__c ip : [select TerminalClient__c,TerminalClient__r.Name from IntentProduct__c where Opportunity__c in:oppIds and TerminalClient__c != null ]){

            accMap.put(ip.TerminalClient__r.Name,ip.TerminalClient__c );
        }
        accMapJson = JSON.serialize(accMap);

    }




    public void setApplicableCustomers(){

        opp.TerminalCustomer__c = appAccId;
        opp.Corpcode__c = appCompany;
        System.debug('setApplicableCustomers==>'+ appAccId);
    }
    ///初始化
    public void init(){
        try{

            List<Object> data = null;
            Account acc = null;
            if(Id.valueOf(backId).getSObjectType() == Contract__c.SObjectType ){
                isNew = false ;

                con = [select Id,Opportunity__c,Account__r.RecordType.DeveloperName,TerminalCustomer__c,
                Account__c,Account__r.Name , Status__c ,Stopped__c ,TerminalCustomer__r.Name 
                from Contract__c where Id=:backId];

                //判断不能操作的情况!
                if(con.Status__c != '草稿' && con.Status__c != 'OA已拒绝' ) setErr('合同'+con.Status__c +'不能操作!');
                if(con.Stopped__c)setErr('合同已终止不能操作!');
                //if(con.Opportunity__c == null )setErr('请先关联业务机会!');
                //获取所有满足条件的业务机会
                //关联的业务机会 或者 合并的业务机会
                for(Opportunity opp :[select Id from Opportunity where Id =: con.Opportunity__c or SucceedOpportunity__c=: con.Opportunity__c]){
                    oppIdset.add(opp.Id );

                } 

                 acc = [select Id ,Name from Account where Id =:con.Account__c];
                isDealer = con.Account__r.RecordType.DeveloperName == 'Dealer';

                data = getDetails();


                         
            }else if (Id.valueOf(backId).getSObjectType() == Account.SObjectType  ){
                isNew = true;

                Opportunity opp1 = [select Id ,StageName,RecordType.DeveloperName  from Opportunity where Id =:oppId ];

                if((opp.RecordType.DeveloperName  == 'CustomerOpportunity' && opp.StageName != '招标') && (opp.RecordType.DeveloperName  ==   'DealerOpportunity' && opp.StageName != '方案谈判') )throw new DmlException(opp.StageName +'阶段不能新建合同!');
                con = new Contract__c();
                con.RecordTypeId = Utils.getRecordTypeIdByDevNameAndObjName('TerminalContract', 'Contract__c');
                con.Status__c = '草稿';
                List<Opportunity> oppList = ( List<Opportunity>)SQLUtil.query('select Id from Opportunity where AccountId = \''+backId+'\' and  StageName != \'合同签订\' and StageName != \'失败\' ' );
                for(Opportunity opp : oppList){
                    oppIdset.add(opp.Id );
                } 
                coCustomer = backId;
                con.Account__c = backId;
                con.ApproveType__c = '0';

                 acc = [select Id ,Name from Account where Id =:backId];
                 List<Object> tmp = getCoopProduct();
                 if(tmp.isEmpty() )throw new DmlException('请先添加合作产品明细!');





            }else if(Id.valueOf(backId).getSObjectType() == Opportunity.SObjectType ){
                isOpp = true;
                 isNew = true;
                //销售员选择业务机会里的产品 生成客户的合作仪器
                opp = [select Id,Corpcode__c,AccountId,Account.Name,RecordType.DeveloperName,StageName,TerminalCustomer__c,TerminalCustomer__r.Name ,Account.RecordType.DeveloperName from Opportunity  where Id =: backId ];
                 acc = [select Id ,Name from Account where Id =:opp.AccountId ];

                coCustomer = opp.AccountId;
                isDealer = opp.Account.RecordType.DeveloperName == 'Dealer';
                if(!System.Test.isRunningTest()&& opp.StageName != '招标' && opp.RecordType.DeveloperName == 'CustomerOpportunity' )throw new DmlException('终端业务机会在招标阶段才能添加合作明细!');
                if(!System.Test.isRunningTest()&&opp.StageName != '方案谈判' && opp.RecordType.DeveloperName == 'DealerOpportunity' )throw new DmlException('渠道建设业务机会在方案谈判阶段才能添加合作明细!');

                if(opp.StageName == '合同签订' || opp.StageName == '失败')throw new DmlException('业务机会阶段:'+opp.StageName +',不能操作!');
                for(Opportunity opp1 :[select Id from Opportunity where  SucceedOpportunity__c=:backId  and  StageName != '合同签订' and StageName != '失败' ]){
                    oppIdset.add(opp1.Id ); 
                } 
                oppIdset.add(backId);



                data = getNewDetails();

            }else{
                setErr('页面打开错误!');
            }
            //获取终端客户
            getIntentTerinalAccount(oppIdset);
            //获取仪器进入方式   
            getCombobox(); 
            getCompanybobox();

           

            Map<String,Object> dataMap= new Map<String,Object>();
             dataMap.put('data',data);
              //字段
            Map<String,Set<String>> fieldsmap = getFields();
             //字段详情
            Map<String, List<DataUtil.FieldBean>> fbMap = DataUtil.getFieldsBean(fieldsmap,stageObjectMap);
            
            //字段赋值
            Map<String,List<DataUtil.FieldBean>> fields = DataUtil.setFieldsValue(fbMap,DataUtil.getBaseInfo(fbMap,stageObjectMap) );
            
             if(isNew){
                List<DataUtil.FieldBean> conFields =fields.get('Contract__c');
                for ( DataUtil.FieldBean f : conFields) {
                    
                    if(f.name == 'Account__c'){

                        Map<String,String> val = new Map<String,String>();
                        val.put('Name', acc.Name);
                        val.put('Id', acc.Id);
                        f.value = val;
                    }
                    if(f.name == 'ApproveType__c'){
                        f.value = con.ApproveType__c;
                    }
                }

             }
                

            
            dataMap.put('base',fields);
            dataMap.put('baseObject',DataUtil.getBaseObjectMap(stageObjectMap));
            dataJson = EncodingUtil.urlEncode(JSON.serialize(dataMap),'UTF-8');


        }catch(Exception e){
            isErr = true;
            ApexPages.addMessage( new ApexPages.Message(ApexPages.Severity.ERROR ,e.getMessage()));
        }

    }

    public void search(){
        
        Map<String,Object> searchMap = (Map<String,Object>)JSON.deserializeUntyped(EncodingUtil.urlDecode(searchJson, 'UTF-8'));
         Account acc = [select Id ,System__c from Account where Id= :coCustomer];

         String sql = 'select Id,Name ,ContractNum__c from Contract__c  where  Status__c = \'已生效\' and  Stopped__c = false and RecordType.DeveloperName =  \'TerminalContract\' ';
       
        sql +=   acc.System__c  == '大家检验' ? ' and (Account__c = \''+coCustomer+'\'   or  (Account__r.System__c = \'大家检验\' and AllProducts__c = true ) ) '  : ' and Account__c = \''+coCustomer+'\' ' ;

        if(String.isNotBlank((String) searchMap.get('Name'))) sql+= ' and  Name like \'%'+searchMap.get('Name')+'%\' ';
        if(String.isNotBlank((String) searchMap.get('ContractNum__c'))) sql+= ' and  ContractNum__c like \'%'+searchMap.get('ContractNum__c')+'%\' ';

        sql += ' limit 20 ';
                System.debug(sql);

        List<Object> tmp = new List<Object>();
        for (Contract__c c  : Database.query(sql) ) {
            tmp.add(c.getPopulatedFieldsAsMap());
        }
        dataJson = EncodingUtil.urlEncode(JSON.serialize(tmp), 'UTF-8');
    }
    //通知助理 去做合同
    public void noteAssis(){

        Opportunity opp = [select Id,Notice2__c from Opportunity where Id=:oppId];

        if(opp.Notice2__c != null ){
            
            msg = '已通知助理,不要重复通知!';
        }else{
            opp.Notice2__c = System.today();
            update opp;

            msg = '已通知助理!';
        }
    }
     public Map<String,Set<String>>  getFields(){

            Map<String,Set<String>> fieldsMap  = new  Map<String,Set<String>>();
            DataUtil.SObjectBean sb = new DataUtil.SObjectBean();

            sb.title =''; 
            sb.objname = 'Contract__c';
            sb.stype = DataUtil.getSObjectType(sb.objname );
            if(!isNew)sb.idvalue = con.Id;
            sb.type = 'base';
            if(!isNew)sb.condition = ' where Id =\''+con.Id+'\'';
            stageObjectMap.put(sb.objname ,sb );
            Set<String>  fields = new Set<String>{'ApproveType__c','CooperationType__c','ContractSource__c','CustomerContact__c','CooperationType__c','Corpcode__c','Maccura__c','Account__c' };
    
            fieldsMap.put(sb.objname , fields);

        return fieldsMap;
    }

    private void  getCombobox(){
        Map<String,String> comboxs = ImportObject.getPicklistValues('ContractProduct__c', 'EnterWay__c', true);
        List<Object> combos = new List<Object>();
        for(String key : comboxs.keySet()){
            Map<String,String> opt = new Map<String,String>();
            opt.put('id', key);
            opt.put('text',comboxs.get(key));
            combos.add(opt);
        }
        combobx =  EncodingUtil.urlEncode(JSON.serialize(combos),'UTF-8');
    }
    private void  getCompanybobox(){
        Map<String,String> comboxs = ImportObject.getPicklistValues('Opportunity', 'Corpcode__c', true);

        List<Object> combos = new List<Object>();
        for(String key : comboxs.keySet()){
            Map<String,String> opt = new Map<String,String>();
            opt.put('id', key);
            opt.put('text',comboxs.get(key));
            combos.add(opt);
        }
        companybobx =  EncodingUtil.urlEncode(JSON.serialize(combos),'UTF-8');
    }

    private  List<CProductBean> getDetails(){
        
            List<CProductBean> tmp = new List<CProductBean>();
            for(ContractProduct__c cp : [select Id,Product__c ,Product__r.ProductName__c ,Product__r.Brand__c , Product__r.InstrumentType__c,
                Product__r.Spec__c,Product__r.NCCode__c,Product__r.SerialNo__c,Product__r.Model__c,OriginNumber__c,
                QuoteProduct__c,QuoteProduct__r.Quote__c,QuoteProduct__r.Quote__r.Name ,Product__r.MatchingInstrument__c,
                Measure_Calculate_Product__c,Measure_Calculate_Product__r.Measure_Calculate__c,Measure_Calculate_Product__r.Measure_Calculate__r.Name ,
                InstrumentPolicy__c,InstrumentPolicy__r.InstrumentPolicy__c,InstrumentPolicy__r.InstrumentPolicy__r.Name ,
                Quantity__c,SalesPrice__c,LastModifiedDate,EndCustomer__c,EndCustomer__r.Name,
                InstrumentPolicy__r.FreeGift__c,EnterWay__c,Product__r.Category0__c,Opportunity__r.OppNo__c,
                BloodSugarOrderDetail1__c,BloodSugarOrderDetail1__r.BloodSugarOrder__c,BloodSugarOrderDetail1__r.BloodSugarOrder__r.Name 

             from ContractProduct__c where Contract__c =:con.Id  ]){

                tmp.add(new CProductBean(cp));



            }

            for(ContractReagentInformation__c cp : [select Id,ReagentProducts__c ,ReagentProducts__r.ProductName__c ,ReagentProducts__r.Brand__c , 
                ReagentProducts__r.Spec__c,ReagentProducts__r.NCCode__c,ReagentProducts__r.SerialNo__c,ReagentProducts__r.Model__c,
                QuoteProduct__c,QuoteProduct__r.Quote__c,QuoteProduct__r.Quote__r.Name ,Opportunity__r.OppNo__c,
                Measure_Calculate_Product__c,Measure_Calculate_Product__r.Measure_Calculate__c,Measure_Calculate_Product__r.Measure_Calculate__r.Name ,
                Price__c,LastModifiedDate,ReagentProducts__r.Category0__c

             from ContractReagentInformation__c where Contract__c =:con.Id  ]){

                tmp.add(new CProductBean(cp));


            }
            //简易测算
            /*
            for(Measure_Calculate__c mc : [select Id,Name,TerminalName__c,TerminalName__r.Name from Measure_Calculate__c where Contract__c =:con.Id and RecordType.DeveloperName = 'SimpleCalculation'   ]){


                tmp.add(new CProductBean(mc));

            }
            */


        return tmp;


    }

    private  List<CProductBean> getNewDetails(){
        
            List<CProductBean> tmp = new List<CProductBean>();
            for(ContractProduct__c cp : [select Id,Product__c ,Product__r.ProductName__c ,Product__r.Brand__c , Product__r.InstrumentType__c,
                Product__r.Spec__c,Product__r.NCCode__c,Product__r.SerialNo__c,Product__r.Model__c,OriginNumber__c,
                QuoteProduct__c,QuoteProduct__r.Quote__c,QuoteProduct__r.Quote__r.Name ,Product__r.MatchingInstrument__c,
                Measure_Calculate_Product__c,Measure_Calculate_Product__r.Measure_Calculate__c,Measure_Calculate_Product__r.Measure_Calculate__r.Name ,
                InstrumentPolicy__c,InstrumentPolicy__r.InstrumentPolicy__c,InstrumentPolicy__r.InstrumentPolicy__r.Name ,
                Quantity__c,SalesPrice__c,LastModifiedDate,EndCustomer__c,EndCustomer__r.Name,
                InstrumentPolicy__r.FreeGift__c,EnterWay__c,Product__r.Category0__c,Opportunity__r.OppNo__c,
                BloodSugarOrderDetail1__c,BloodSugarOrderDetail1__r.BloodSugarOrder__c,BloodSugarOrderDetail1__r.BloodSugarOrder__r.Name 

             from ContractProduct__c where Opportunity__c =:backId ]){

                tmp.add(new CProductBean(cp));

            }  

             for(ContractReagentInformation__c cp : [select Id,ReagentProducts__c ,ReagentProducts__r.ProductName__c ,ReagentProducts__r.Brand__c , 
                ReagentProducts__r.Spec__c,ReagentProducts__r.NCCode__c,ReagentProducts__r.SerialNo__c,ReagentProducts__r.Model__c,
                QuoteProduct__c,QuoteProduct__r.Quote__c,QuoteProduct__r.Quote__r.Name ,Opportunity__r.OppNo__c,
                Measure_Calculate_Product__c,Measure_Calculate_Product__r.Measure_Calculate__c,Measure_Calculate_Product__r.Measure_Calculate__r.Name ,
                Price__c,LastModifiedDate,ReagentProducts__r.Category0__c

             from ContractReagentInformation__c where Opportunity__c =:backId ]){

                tmp.add(new CProductBean(cp));


            } 

        return tmp;

    }

    public List<CProductBean> getCoopProduct(){
       
        List<CProductBean> tmp = new List<CProductBean> (); 
        
        for(ContractProduct__c cp : [select Id,Product__c ,Product__r.ProductName__c ,Product__r.Brand__c , Product__r.InstrumentType__c,
                Product__r.Spec__c,Product__r.NCCode__c,Product__r.SerialNo__c,Product__r.Model__c,OriginNumber__c,
                QuoteProduct__c,QuoteProduct__r.Quote__c,QuoteProduct__r.Quote__r.Name ,Product__r.MatchingInstrument__c,
                Measure_Calculate_Product__c,Measure_Calculate_Product__r.Measure_Calculate__c,Measure_Calculate_Product__r.Measure_Calculate__r.Name ,
                InstrumentPolicy__c,InstrumentPolicy__r.InstrumentPolicy__c,InstrumentPolicy__r.InstrumentPolicy__r.Name ,
                Quantity__c,SalesPrice__c,LastModifiedDate,EndCustomer__c,EndCustomer__r.Name,
                InstrumentPolicy__r.FreeGift__c,EnterWay__c,Product__r.Category0__c,Opportunity__r.OppNo__c,
                BloodSugarOrderDetail1__c,BloodSugarOrderDetail1__r.BloodSugarOrder__c,BloodSugarOrderDetail1__r.BloodSugarOrder__r.Name 

             from ContractProduct__c where CoCustomer__c =:con.Account__c  and  Contract__c = null ]){

                tmp.add(new CProductBean(cp));

        }

        for(ContractReagentInformation__c cp : [select Id,ReagentProducts__c ,ReagentProducts__r.ProductName__c ,ReagentProducts__r.Brand__c , 
                ReagentProducts__r.Spec__c,ReagentProducts__r.NCCode__c,ReagentProducts__r.SerialNo__c,ReagentProducts__r.Model__c,
                QuoteProduct__c,QuoteProduct__r.Quote__c,QuoteProduct__r.Quote__r.Name ,Opportunity__r.OppNo__c,
                Measure_Calculate_Product__c,Measure_Calculate_Product__r.Measure_Calculate__c,Measure_Calculate_Product__r.Measure_Calculate__r.Name ,
                Price__c,LastModifiedDate,ReagentProducts__r.Category0__c

             from ContractReagentInformation__c where CoCustomer__c =:con.Account__c and  Contract__c = null  ]){

                tmp.add(new CProductBean(cp));


            }

         return tmp;


    }
    public void getProduct(){
        Map<String,Object> searchMap = (Map<String,Object> )JSON.deserializeUntyped(searchJson);
        String type =  String.valueOf( searchMap.get('type'));
        List<CProductBean> tmp = new List<CProductBean> (); 
        if(type == 'QuoteEquipment'){
            tmp = getQuoteEquipment();
        }else if(type == 'QuoteRegent'){
            tmp = getQuoteRegent();
        }else if(type == 'MeasureCalc'){
            tmp = getMeasureCalc();
        }else if(type == 'Policy'){
            tmp = getPolicy();
        }else if(type == 'Blood'){
           tmp =  getBloodOrder();
        }else if(type == 'CoopProduct'){
            tmp = getCoopProduct();
        }
        System.debug('ContractProduct==>'+ tmp );
        dataJson = EncodingUtil.urlEncode(JSON.serialize(tmp),'UTF-8');

    }
    private List<CProductBean> getQuote(Boolean isEq){
        String type = isEq ? '仪器报价' : '试剂报价' ; 
        List<CProductBean> tmp = new List<CProductBean> (); 
        System.debug('ContractProduct==>'+ oppIdset );
        for(QuoteProduct__c qp : [select Id ,Quote__c,Quote__r.Name,Product__c ,Product__r.ProductName__c ,Product__r.Brand__c ,
           Product__r.SerialNo__c,Product__r.NCCode__c,Product__r.Spec__c,Product__r.Model__c,Quantity__c,SalesPrice__c ,LastModifiedDate,
           Quote__r.Opportunity.OppNo__c,
           Account__c,Account__r.Name ,Product__r.MatchingInstrument__c,Product__r.Category0__c,Product__r.InstrumentType__c
         from QuoteProduct__c 
            where Quote__r.OpportunityId in:oppIdset and  Quote__r.Status = '已批准' and Quote__r.IsActive__c = true  and Quote__r.Type__c = : type ]){
            
            tmp.add(new CProductBean(qp,isEq ));

        }
        return tmp ;


    }

    ///从血糖仪配送申请 中选择
    private List<CProductBean> getBloodOrder(){
        List<CProductBean> tmp = new List<CProductBean> (); 

        for(BloodSugarOrderDetail__c bld: [select Id, DistributionProduct__c ,DistributionProduct__r.ProductName__c, DistributionProduct__r.Brand__c,DistributionProduct__r.Spec__c,DistributionProduct__r.Category0__c,
            BloodSugarOrder__r.Opportunities__r.OppNo__c,
        DistributionProduct__r.Model__c,DistributionProduct__r.SerialNo__c , BloodSugarOrder__c ,BloodSugarOrder__r.Name , DistributionProductNumber__c ,DistributionProduct__r.NCCode__c,LastModifiedDate
            from BloodSugarOrderDetail__c where BloodSugarOrder__r.Opportunities__c in:oppIdset and BloodSugarOrder__r.Status__c = '审批成功' and BloodSugarOrder__r.Effect__c = true   ]){
            tmp.add(new CProductBean(bld));

        }
        return tmp ;


    }
    ///从有效的仪器报价中选择
    private List<CProductBean> getQuoteEquipment( ){
        return getQuote(true);
        

    }
    ///从有效的试剂报价中选择
    private List<CProductBean> getQuoteRegent(){
        return getQuote(false);

    }
    ///从有效的测算中选择
    private List<CProductBean> getMeasureCalc( ){
        List<CProductBean> tmp = new List<CProductBean> (); 

        for(Measure_Calculate_Product__c ip  : [select Id ,Measure_Calculate__c ,Measure_Calculate__r.Name,Product__c ,Product__r.ProductName__c ,Product__r.Brand__c ,
           Product__r.SerialNo__c,Product__r.NCCode__c,Product__r.Spec__c,Product__r.Model__c,Quantity__c,SalesPriceWT__c,IsEquipRelated__c,LastModifiedDate,Product__r.Category0__c,
           Measure_Calculate__r.Opportunity__r.OppNo__c,
           Measure_Calculate__r.TerminalName__c,Measure_Calculate__r.TerminalName__r.Name ,Product__r.MatchingInstrument__c,Product__r.InstrumentType__c
         from Measure_Calculate_Product__c 
            where Measure_Calculate__r.Opportunity__c in:oppIdset and  Measure_Calculate__r.Status__c = '审批成功' and Measure_Calculate__r.IsActive__c = true 
            and Measure_Calculate__r.RecordType.DeveloperName != 'SimpleCalculation'  ]){
            tmp.add(new CProductBean(ip));

        }

        //简易测算
        for(Measure_Calculate__c mc : [select Id,Name,TerminalName__c,TerminalName__r.Name,Opportunity__r.OppNo__c from Measure_Calculate__c where  Opportunity__c in:oppIdset and 
         Status__c = '审批成功' and IsActive__c = true  and RecordType.DeveloperName = 'SimpleCalculation'   ]){
             tmp.add(new CProductBean(mc));

        }
        return tmp ;
    }
    ///从有效的政策中选择
    private List<CProductBean> getPolicy( ){
        List<CProductBean> tmp = new List<CProductBean> (); 
        for(InstrumentMarketingPolicy__c ip  : [select Id ,InstrumentPolicy__c ,InstrumentPolicy__r.Name,Product__c ,Product__r.ProductName__c ,Product__r.Brand__c ,
           Product__r.SerialNo__c,Product__r.NCCode__c,Product__r.Spec__c,Product__r.Model__c,Quantity__c, SalePrice__c,LastModifiedDate,Product__r.InstrumentType__c,
           InstrumentPolicy__r.Opportunity__r.OppNo__c , 
           TerminalAccunt__c,TerminalAccunt__r.Name ,Product__r.MatchingInstrument__c,Product__r.Category0__c,FreeGift__c 
         from InstrumentMarketingPolicy__c 
            where InstrumentPolicy__r.Opportunity__c in:oppIdset and  InstrumentPolicy__r.Status__c = '已批准' and InstrumentPolicy__r.Active__c = true   ]){
            
            tmp.add(new CProductBean(ip));

        }
        return tmp;


    }
    private Id getIdvalue(Object o ){

        if(o == null ) return null;
        return Id.valueOf(String.valueOf(o));
    }


    public  void saveContract(){
        try {
            msg = '';

            Map<String , Object> saveMap = (Map<String ,Object>)JSON.deserializeUntyped(EncodingUtil.urlDecode(saveJson,'UTF-8'));

            Map<String,Object> baseMap = (  Map<String,Object>)saveMap.get('base');

            Map<String,Set<String>> fieldsMap = getFields();
            Map<String,DataUtil.FieldBean> fbeanMap = DataUtil.getFieldsInfo(Contract__c.SObjecttype,fieldsMap.get('Contract__c'));
            for(String field : baseMap.keySet()){
                con.put(field, DataUtil.dataHandler(baseMap.get(field),fbeanMap.get(field).type.toUpperCase() ));
            }


           // String accId = saveMap.get('account') == null ? null : String.valueOf(saveMap.get('account'));

           // con.TerminalCustomer__c = String.isBlank(accId )? con.Account__c : accId;


            List<Object> cpList = ( List<Object> )saveMap.get('data');
            List<ContractProduct__c> cElist = new List<ContractProduct__c>();
            List<ContractReagentInformation__c> cRlist = new List<ContractReagentInformation__c>();

            Set<Id> setIds = new Set<Id>();
            for(Object o : cpList){

                Map<String,Object> mo = (Map<String,Object>)o ; 
                Boolean isEq = Boolean.valueOf(String.valueOf(mo.get('isEq')));
                Id recordId =  getIdvalue(mo.get('sid'));
                if(recordId == null&& !System.Test.isRunningTest())throw new DmlException('异常数据!');
                setIds.add(recordId);
                if(isEq){
                    ContractProduct__c cp = new ContractProduct__c();
                    cp.Id = recordId; 
                    cElist.add(cp);
                }else{
                    ContractReagentInformation__c cp = new ContractReagentInformation__c();
                    cp.Id = recordId; 
                    cRlist.add(cp);
                }

            }
          

            SavePoint sp = Database.setSavepoint();
            try {
            
                upsert con;

                for(ContractProduct__c cp : cElist){
                    cp.Contract__c = con.Id;
                }

                for(ContractReagentInformation__c cp : cRlist){
                    cp.Contract__c = con.Id;
                }
                List<ContractProduct__c> cpL =  [select Id , Contract__c from ContractProduct__c where Id not in: setIds and Contract__c =:con.Id  ];
                for (ContractProduct__c cp : cpL ) {
                    cp.Contract__c = null;
                    cElist.add(cp);

                }
                List<ContractReagentInformation__c> crL =  [select Id , Contract__c from ContractReagentInformation__c where Id not in: setIds and Contract__c =:con.Id  ];
                for (ContractReagentInformation__c cp : crL ) {
                    cp.Contract__c = null;
                    cRlist.add(cp);

                }
                update cElist;
                update cRlist;
                backId = con.Id;
                isSuccess = true;
                msg = '保存成功!';
            }catch (Exception e) {
                Database.rollback(sp);
                msg = '保存失败:'+e.getMessage()+e.getStackTraceString();
            }
            

        }catch (Exception e) {
            msg = '保存失败:'+e.getMessage();
        }
        System.debug('ContractProductController==>'+msg);
    }
    /*
    public void save(){

        try {
            msg = '';
            Map<String,Object> saveMap  = (Map<String,Object>) JSON.deserializeUntyped(EncodingUtil.urlDecode(saveJson, 'UTF-8'));

            String accId = saveMap.get('account') == null ? null : String.valueOf(saveMap.get('account'));

            con.TerminalCustomer__c = String.isBlank(accId )? con.Account__c : accId;

            List<Object> cpList = ( List<Object> )saveMap.get('data');
            List<ContractProduct__c> cElist = new List<ContractProduct__c>();
            List<ContractReagentInformation__c> cRlist = new List<ContractReagentInformation__c>();

            Set<Id> setIds = new Set<Id>();
            for(Object o : cpList){

                Map<String,Object> mo = (Map<String,Object>)o ; 
                Boolean isEq = Boolean.valueOf(String.valueOf(mo.get('isEq')));
                Boolean isSimpleMc = Boolean.valueOf(String.valueOf(mo.get('isSimpleMc')));

                if(mo.get('mcId') != null )setIds.add(getIdvalue(mo.get('mcId')));
                if(mo.get('quoteId')!= null)setIds.add(getIdvalue(mo.get('quoteId')));
                if(mo.get('policyId')!= null)setIds.add(getIdvalue(mo.get('policyId')));
                if(mo.get('bloodId')!= null)setIds.add(getIdvalue(mo.get('bloodId')));



                if(isSimpleMc)continue;
                if(isEq){
                    cElist.add(genEquip(mo));
                }else{
                    cRlist.add(genRegent(mo));
                }

            }
          //  List<SObject> sList = new List<SObject>();
            //List<Quote> qList = new List<Quote>();
            //关联合同 取消关联合同
            Map<Id  , SObject> sMap = new Map<Id,SObject>();
            for(Quote q:  [select Id,Contract__c from Quote  where Contract__c =:con.Id  ]){
                if(!setIds.contains(q.Id )){
                    q.Contract__c = null;
                    sMap.put(q.Id , q);
                }
            }

            for(Measure_Calculate__c mc : [select Id,Contract__c from Measure_Calculate__c  where Contract__c =:con.Id  ]){
                 if(!setIds.contains(mc.Id )){
                    mc.Contract__c = null;
                    sMap.put(mc.Id,mc );
                }
            }
            for(InstrumentPolicy__c ip : [select Id,Contract__c from InstrumentPolicy__c  where Contract__c =:con.Id ]){

                if(!setIds.contains(ip.Id )){
                    ip.Contract__c = null;
                    sMap.put(ip.Id,ip );
                }

            }

             for(BloodSugarOrder__c ip : [select Id,Contract__c from BloodSugarOrder__c  where Contract__c =:con.Id ]){

                if(!setIds.contains(ip.Id )){
                    ip.Contract__c = null;
                    sMap.put(ip.Id,ip );
                }

            }

            for(Id sid : setIds){
                SObject so = sid.getSobjectType().newSObject();
                so.put('Id', sid);
                so.put('Contract__c',con.Id);
                sMap.put(sid, so);
            }

            SavePoint sp = Database.setSavepoint();
            try {
              

                delete [select Id from ContractProduct__c where Contract__c =:con.Id ];
                delete [select Id from ContractReagentInformation__c where Contract__c =:con.Id ];

                if(cElist.size() > 0 ) insert cElist;
                 System.debug(cRlist);
                if(cRlist.size() > 0 ) insert cRlist;

                if(sMap.values().size() > 0 ) update sMap.values();
                update con;
                isSuccess = true;
                msg = '保存成功!';
            }catch (Exception e) {
                Database.rollback(sp);
                msg = '保存失败:'+e.getMessage()+e.getStackTraceString();
            }
            

        }catch (Exception e) {
            msg = '保存失败:'+e.getMessage();
        }
        System.debug('ContractProductController==>'+msg);
        

    }
*/

    ///保存合仪器到客户和业务机会下
    public void newSave(){

        try {

            msg = '';
            Map<String,Object> saveMap  = (Map<String,Object>) JSON.deserializeUntyped(EncodingUtil.urlDecode(saveJson, 'UTF-8'));

            List<Object> cpList = ( List<Object> )saveMap.get('data');
            List<ContractProduct__c> cElist = new List<ContractProduct__c>();
            List<ContractReagentInformation__c> cRlist = new List<ContractReagentInformation__c>();

            Set<Id> setIds = new Set<Id>();
            for(Object o : cpList){

                Map<String,Object> mo = (Map<String,Object>)o ; 
                Boolean isEq = Boolean.valueOf(String.valueOf(mo.get('isEq')));
                Boolean isSimpleMc = Boolean.valueOf(String.valueOf(mo.get('isSimpleMc')));

                Id recordId =  getIdvalue(mo.get('sid'));
                if(recordId != null )setIds.add(recordId);



                if(isSimpleMc)continue;
                if(isEq){
                     ContractProduct__c cp  = genEquip(mo);
                     cp.Opportunity__c = backId; 
                    cp.CoCustomer__c = coCustomer;
                    cp.Id = recordId;
                    cElist.add(cp);
                }else{
                    ContractReagentInformation__c cp  = genRegent(mo);
                    cp.Opportunity__c = backId; 
                    cp.CoCustomer__c = coCustomer;
                    cp.Id = recordId;
                   cRlist.add(cp);


                }
                


            }
          
            SavePoint sp = Database.setSavepoint();
            try {
                
                //删除业务机会下原来的的合作仪器
                List<ContractProduct__c> deList =  [select Id,Contract__c ,Product__r.ProductName__c  from ContractProduct__c where Opportunity__c =:backId  and Id not in: setIds  ];
                for ( ContractProduct__c cp : deList) {
                    if(cp.Contract__c != null ){
                        throw new DmlException(cp.Product__r.ProductName__c  +'已生成合同不能删除!');
                    }
                }


                if(!deList.isEmpty())delete deList;

                delete [select Id from ContractReagentInformation__c where Id not in:setIds and   Opportunity__c =:backId  ];

                if(cElist.size() > 0 ) upsert  cElist;
                 System.debug(cRlist);
                if(cRlist.size() > 0 ) upsert cRlist;

                //if(sMap.values().size() > 0 ) update sMap.values();
                isSuccess = true;
                update opp;
                msg = '保存成功!';
            }catch (Exception e) {
                Database.rollback(sp);
                msg = '保存失败:'+e.getMessage()+e.getStackTraceString();
            }
            

        }catch (Exception e) {
            msg = '保存失败:'+e.getMessage();
        }
        System.debug('ContractProductController==>'+msg);
        

    }

    private ContractProduct__c genEquip(Map<String,Object> mo){
        //存产品的品牌+规格+品名
        ContractProduct__c cp = new ContractProduct__c();
        cp.Product__c =  DataUtil.getStringValue(mo.get('productId'));
        cp.Quantity__c = DataUtil.getDecimalValue(mo.get('num'));
        cp.OriginNumber__c =  DataUtil.getDecimalValue(mo.get('num'));
        cp.SalesPrice__c = DataUtil.getDecimalValue(mo.get('price'));
        cp.QuoteProduct__c = DataUtil.getStringValue(mo.get('quoteDetailId'));
        cp.Measure_Calculate_Product__c =  DataUtil.getStringValue(mo.get('mcDetailId'));
        cp.InstrumentPolicy__c = DataUtil.getStringValue(mo.get('policyDetailId'));
        cp.BloodSugarOrderDetail1__c = DataUtil.getStringValue(mo.get('bloodDetailId'));
        cp.EndCustomer__c = DataUtil.getStringValue(mo.get('terminalId'));
        cp.EnterWay__c =  DataUtil.getStringValue(mo.get('enterway')); 

        cp.CoopType__c = cp.QuoteProduct__c == null || cp.BloodSugarOrderDetail1__c == null  ? '投放' : '正常销售';
        String isForSale = DataUtil.getStringValue(mo.get('isForSale'));
        //小型仪器 价格不为0 政策的指定赠送仪器 报价仪器 都默认为 : 正常销售
        if( isForSale != null  && Boolean.valueOf(isForSale) == true ) cp.CoopType__c = '正常销售';
        if( cp.SalesPrice__c !=null && cp.SalesPrice__c > 0 )cp.CoopType__c = '正常销售';

        return cp ; 
    }

    private ContractReagentInformation__c genRegent(Map<String,Object> mo ){
        //存产品的品牌+规格+品名
        ContractReagentInformation__c cp  = new ContractReagentInformation__c();
        //cp.Name = DataUtil.getStringValue(mo.get('quoteDetailId'))+ DataUtil.getStringValue(mo.get('quoteDetailId')) + DataUtil.getStringValue(mo.get('quoteDetailId'))
        cp.Price__c = DataUtil.getDecimalValue(mo.get('price'));
        cp.QuoteProduct__c = DataUtil.getStringValue(mo.get('quoteDetailId'));
        cp.Measure_Calculate_Product__c =  DataUtil.getStringValue(mo.get('mcDetailId'));
        cp.ReagentProducts__c = DataUtil.getStringValue(mo.get('productId'));
        return cp;
    }


    public class CProductBean{

        public String productName ;
        public String productId ; 

        public String brand ;
        public String spec ; 
        public String nccode ; 
        public String serialno;
        public String model;
        public String cate0;

        public String quoteName ;
        public String mcName ; 
        public String policyName ; 
        public String bloodName;
        public String oppName;

        public String quoteId ; 
        public String mcId ; 
        public String policyId ; 
        public String bloodId;

        public String quoteDetailId ; 
        public String mcDetailId  ; 
        public String policyDetailId ;
        public String bloodDetailId;
        public String enterway;


    
        public Boolean isForSale;//是否为小型仪器 和 仪器配套赠送仪器 默认为正常销售


        public Decimal num ; //数量
        public Decimal price ; //价格

        public String terminalId ; //终端客户
        public String terminal;//终端客户名称

        public Boolean isEq ;//是否是仪器

        public String originId ; //来源Id
        public String detailId ; //明细Id 
        public String ts ; //修改时间

        public String sid ; //合作明细id;

        public String relatedId;//配套Id 


        public Boolean isSimpleMc ; //是否


        public CProductBean(ContractProduct__c qp ){
            sid = qp.Id ;
            productId = qp.Product__c ; 
            productName  = qp.Product__r.ProductName__c;
            enterway = qp.EnterWay__c;

            cate0 = qp.Product__r.Category0__c;

            brand = qp.Product__r.Brand__c;
            spec = qp.Product__r.Spec__c;
            nccode = qp.Product__r.NCCode__c;
            serialno = qp.Product__r.SerialNo__c;
            model = qp.Product__r.Model__c;
         
            isForSale = qp.Product__r.InstrumentType__c == '非维保仪器';

            if(qp.InstrumentPolicy__r.FreeGift__c == true ) isForSale = true;
            oppName = qp.Opportunity__r.OppNo__c;
            quoteDetailId = qp.QuoteProduct__c;
            quoteId = qp.QuoteProduct__r.Quote__c;
            quoteName = qp.QuoteProduct__r.Quote__r.Name ;

            mcDetailId = qp.Measure_Calculate_Product__c;
            mcId = qp.Measure_Calculate_Product__r.Measure_Calculate__c;
            mcName = qp.Measure_Calculate_Product__r.Measure_Calculate__r.Name ;

            policyId = qp.InstrumentPolicy__r.InstrumentPolicy__c;
            policyName = qp.InstrumentPolicy__r.InstrumentPolicy__r.Name;

            bloodId = qp.BloodSugarOrderDetail1__r.BloodSugarOrder__c;
            bloodName = qp.BloodSugarOrderDetail1__r.BloodSugarOrder__r.Name ;
            bloodDetailId = qp.BloodSugarOrderDetail1__c;

            policyDetailId = qp.InstrumentPolicy__c ; 
            terminalId = qp.EndCustomer__c;
            terminal = qp.EndCustomer__r.Name;

            num = qp.OriginNumber__c;

            price = qp.SalesPrice__c;

            originId = quoteId != null ? quoteId : mcId != null ? mcId : policyId != null ? policyId : bloodId != null ?bloodId:null   ;
            detailId = mcDetailId != null ? mcDetailId : quoteDetailId != null ? quoteDetailId : policyDetailId != null ? policyDetailId : bloodDetailId != null ? bloodDetailId : null  ; 

            isEq = true;
            ts = qp.LastModifiedDate == null ? '' :  qp.LastModifiedDate.format('yyyy-MM-dd HH:mm:ss');
            isSimpleMc = false;

            relatedId = qp.Product__r.MatchingInstrument__c;
        }
        public CProductBean(ContractReagentInformation__c qp ){
             oppName = qp.Opportunity__r.OppNo__c;
            productId = qp.ReagentProducts__c ; 
            productName  = qp.ReagentProducts__r.ProductName__c;
            sid = qp.Id;

            cate0 = qp.ReagentProducts__r.Category0__c;

            brand = qp.ReagentProducts__r.Brand__c;
            spec = qp.ReagentProducts__r.Spec__c;
            nccode = qp.ReagentProducts__r.NCCode__c;
            serialno = qp.ReagentProducts__r.SerialNo__c;
            model = qp.ReagentProducts__r.Model__c;
        
            quoteDetailId = qp.QuoteProduct__c;
            quoteId = qp.QuoteProduct__r.Quote__c;
            quoteName = qp.QuoteProduct__r.Quote__r.Name ;

            mcDetailId = qp.Measure_Calculate_Product__c;
            mcId = qp.Measure_Calculate_Product__r.Measure_Calculate__c;
            mcName = qp.Measure_Calculate_Product__r.Measure_Calculate__r.Name ;

            
            price = qp.Price__c;

            originId = quoteId != null ? quoteId : mcId != null ? mcId : null  ;
            detailId = mcDetailId != null ? mcDetailId : quoteDetailId != null ? quoteDetailId : policyDetailId != null ? policyDetailId : null ; 

            isEq = false;
            ts = qp.LastModifiedDate == null ? '' :  qp.LastModifiedDate.format('yyyy-MM-dd HH:mm:ss');
            isSimpleMc = false;

        }

        public CProductBean(QuoteProduct__c qp , Boolean isE){

            productId = qp.Product__c ; 
            productName  = qp.Product__r.ProductName__c;

            cate0 = qp.Product__r.Category0__c;

            brand = qp.Product__r.Brand__c;
            spec = qp.Product__r.Spec__c;
            nccode = qp.Product__r.NCCode__c;
            serialno = qp.Product__r.SerialNo__c;
            model = qp.Product__r.Model__c;
            isForSale = qp.Product__r.InstrumentType__c == '非维保仪器';
            oppName = qp.Quote__r.Opportunity.OppNo__c;
            quoteName = qp.Quote__r.Name;
            quoteId = qp.Quote__c;

            quoteDetailId = qp.Id; 
            num = qp.Quantity__c;
            price = qp.SalesPrice__c;

            terminalId = qp.Account__c; 

            terminal = qp.Account__r.Name ;

            originId = qp.Quote__c;
            detailId = quoteDetailId;
            isEq = isE; 
            ts = qp.LastModifiedDate == null ? '' :  qp.LastModifiedDate.format('yyyy-MM-dd HH:mm:ss');
            isSimpleMc = false;
            relatedId = qp.Product__r.MatchingInstrument__c;

        }
        public CProductBean(InstrumentMarketingPolicy__c qp  ){
            productId = qp.Product__c ; 
            productName  = qp.Product__r.ProductName__c;
            isForSale = qp.Product__r.InstrumentType__c == '非维保仪器';
            cate0 = qp.Product__r.Category0__c;

            oppName = qp.InstrumentPolicy__r.Opportunity__r.OppNo__c ;

            if(qp.FreeGift__c == true ) isForSale = true;
            brand = qp.Product__r.Brand__c;
            spec = qp.Product__r.Spec__c;
            nccode = qp.Product__r.NCCode__c;
            serialno = qp.Product__r.SerialNo__c;
            model = qp.Product__r.Model__c;

            policyName = qp.InstrumentPolicy__r.Name;
            policyId = qp.InstrumentPolicy__c;

            terminalId = qp.TerminalAccunt__c;
            terminal = qp.TerminalAccunt__r.Name;

            policyDetailId = qp.Id; 
            num = qp.Quantity__c;
            price = qp.SalePrice__c;
            originId = qp.InstrumentPolicy__c;
            detailId = policyDetailId;

            ts = qp.LastModifiedDate == null ? '' : qp.LastModifiedDate.format('yyyy-MM-dd HH:mm:ss');

            isEq = true ;
            isSimpleMc = false;
            relatedId = qp.Product__r.MatchingInstrument__c;

        }

        public CProductBean(Measure_Calculate__c qp  ){
            
            oppName = qp.Opportunity__r.Name ;

            mcName = qp.Name ;
            mcId = qp.Id ;
            terminalId = qp.TerminalName__c;
            terminal = qp.TerminalName__r.Name;
            originId = qp.Id;

            isSimpleMc = true;
            isEq = false;
        }
        public CProductBean(Measure_Calculate_Product__c qp  ){
            oppName = qp.Measure_Calculate__r.Opportunity__r.OppNo__c ;
            productId = qp.Product__c ; 
            productName  = qp.Product__r.ProductName__c;
            isForSale = qp.Product__r.InstrumentType__c == '非维保仪器';
            cate0 = qp.Product__r.Category0__c;

            brand = qp.Product__r.Brand__c;
            spec = qp.Product__r.Spec__c;
            nccode = qp.Product__r.NCCode__c;
            serialno = qp.Product__r.SerialNo__c;
            model = qp.Product__r.Model__c;

            mcName = qp.Measure_Calculate__r.Name ;
            mcId = qp.Measure_Calculate__c;
            terminalId = qp.Measure_Calculate__r.TerminalName__c;
            terminal = qp.Measure_Calculate__r.TerminalName__r.Name;

            mcDetailId = qp.Id;

            num = qp.Quantity__c;
            price = qp.SalesPriceWT__c;
            originId = qp.Measure_Calculate__c;
            
            detailId = mcDetailId;
            ts = qp.LastModifiedDate == null ? '' : qp.LastModifiedDate.format('yyyy-MM-dd HH:mm:ss');
            isEq = qp.IsEquipRelated__c ;
            isSimpleMc = false;
            relatedId = qp.Product__r.MatchingInstrument__c;

        }

        public CProductBean(BloodSugarOrderDetail__c qp  ){
            productId = qp.DistributionProduct__c  ; 
            productName  = qp.DistributionProduct__r.ProductName__c ;
            cate0 = qp.DistributionProduct__r.Category0__c;
            oppName = qp.BloodSugarOrder__r.Opportunities__r.OppNo__c ;


            isForSale = true;
            brand = qp.DistributionProduct__r.Brand__c;
            spec = qp.DistributionProduct__r.Spec__c;
            nccode = qp.DistributionProduct__r.NCCode__c;
            serialno = qp.DistributionProduct__r.SerialNo__c;
            model = qp.DistributionProduct__r.Model__c;

            bloodName = qp.BloodSugarOrder__r.Name;
            bloodId = qp.BloodSugarOrder__c;
            bloodDetailId  = qp.Id ;
            //terminalId = qp.Measure_Calculate__r.TerminalName__c;
            //terminal = qp.Measure_Calculate__r.TerminalName__r.Name;


            num = qp.DistributionProductNumber__c;
            //price = qp.SalesPriceWT__c;
            originId = qp.BloodSugarOrder__c  ;
            
            detailId = bloodDetailId;
            ts =qp.LastModifiedDate == null ? '' :  qp.LastModifiedDate.format('yyyy-MM-dd HH:mm:ss');
            isEq = true;
            isSimpleMc = false;
            //relatedId = qp.Product__r.MatchingInstrument__c;

        }

    }







}